package com.ms.game.slot.base;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;

import com.xpec.c4.db.hibernate.manager.HibernateManager;
import com.xpec.c4.db.model.basic.SlotBasicGameModel;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.service.module.BasicServiceModule;

/**
 * slot dm service module
 * @author TW15012
 *
 */
public abstract class SlotDMBasicServiceModule extends BasicServiceModule
{
	/**
	 * 排列帶
	 */
	public static final int TYPE_ARRANGE = 0;
	
	/**
	 * 非排列帶
	 */
	public static final int TYPE_NO_ARRANGE = 1;
	
	
	private static final Log log = LogFactory.getLog(SlotDMBasicServiceModule.class);
	
	/**
	 * 資料庫名稱
	 */
	private String modelName;
	
	/**
	 * 讀取機台資料庫名稱
	 * @return
	 */
	public String getModelName() {
		return modelName;
	}

	@Override
	public void init()
	{
		super.init();
		
		registerActionClass(SlotDMBasicAction.class);
	}
	
	@Override
	public void shutdown() {
		super.shutdown();
	}
	
	/**
	 * 註冊
	 * @param cls
	 */
	protected void registerModelClass(Class<?> cls)
	{
		modelName = cls.getName();
	}
	
	/**
	 * 產生資料庫資料
	 */
	public void createAndCacheModelData(String gameType, String hallType) {
		
		try {
			Class<?> clazz = Class.forName(modelName);
			Constructor<?> ctor = clazz.getConstructor();

			ArrayList<GainRateData> gainRateDatas = GainRateSystem.getGainRateList(gameType, hallType);

			ArrayList<Object> allModels = new ArrayList<Object>();
			
			for(GainRateData gainRateData : gainRateDatas){
				
				//沒開放的跳過
				if(!gainRateData.isOpen()){
					continue;
				}
				
				BigDecimal gainRate = gainRateData.getGainRate();
				int beginMachineID = gainRateData.getBeginMachineID();
				int endMachineID = gainRateData.getEndMachineID();
				
				//取得該比值的所有機台
				Object machineList = getMachineData(clazz.getName(), hallType, gainRate);
				List<SlotBasicGameModel> modelList = castObjToList(machineList);
				
				//已經挑出來的machineIDs
				ArrayList<Integer> machineIDs = new ArrayList<Integer>();
				//可以使用的modelList IDX
				ArrayList<Integer> availableIDXs = new ArrayList<Integer>();
				
				//從現有的機台挑出來
				for(int idxOfList = 0; idxOfList < modelList.size(); idxOfList++){
					SlotBasicGameModel model = modelList.get(idxOfList);
					int foundMachineID = model.getMachineid();
					
					//在此比值的機台編號範圍內
					if(
							!machineIDs.contains(foundMachineID) &&
							foundMachineID >= beginMachineID &&
							foundMachineID <= endMachineID
					)
					{
						allModels.add(model);
						machineIDs.add(foundMachineID);
					}
					else{
						//等下可以使用的IDX
						availableIDXs.add(idxOfList);
					}

				}
				
				//看看這個比值還缺有的是哪幾台
				for(int machineID = beginMachineID; machineID <= endMachineID; machineID++){
					
					//還缺的機台
					if(!machineIDs.contains(machineID)){
						
						//還有機台可以用
						if(availableIDXs.size() > 0){
							
							int idx = availableIDXs.remove(0);
							
							SlotBasicGameModel model = modelList.get(idx);
							//更新現有的機台machineID
							model.setMachineid(machineID);
							createGameMachine(model);
							allModels.add(model);
							machineIDs.add(machineID);
							
						}
						//沒有就新增
						else{
							
							//缺的直接新增
							Object obj = ctor.newInstance();
							
							initModelData(obj, hallType, machineID, gainRate);
							createGameMachine(obj);
							
							allModels.add(obj);
							machineIDs.add(machineID);
							
						}
						
					}

				}
				
			}
			
			initCache(hallType, allModels);
			
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error(GameUtility.getCurMethodName(), e);
			}
		}
	}
	
	/**
	 * 設定model初始值
	 * 需@Override
	 * @param model
	 */
	public void initModelData(Object model, String halltype, int machineid, BigDecimal gainRate) {

	}
	
	/**
	 * 設定快取資料初始值
	 * 需@Override
	 * @param model
	 */
	public void initCache(String halltype , Object list)
	{
		
	}
	
	/**
	 * 讀取機台列表個數
	 * @param TModel
	 * @return
	 */
	public int getMachineCount(Class<?> TModel , String halltype)
	{
		String tablename="";
		String className = TModel.getName();
		Annotation[] annotations = TModel.getAnnotations();
		for(Annotation aa:annotations)
		{
			if(aa instanceof javax.persistence.Table)
			{
				javax.persistence.Table table = (javax.persistence.Table) aa;
				tablename = table.name();	
				break;
			}
		}
		
		//check table exists?
		Connection conn = HibernateManager.getConnection();
		ResultSet rr;
		try 
		{
			rr = conn.getMetaData().getTables(null, null, tablename , null);
			if(!rr.next())
			{
				if(log.isErrorEnabled())
				{
					log.error("HibernateManager [ "+tablename+" ] No Exists !!!");
				}
				
				return -1;
			}
		} 
		catch (SQLException e) 
		{	
			if(log.isErrorEnabled())
			{
				log.error(GameUtility.getCurMethodName(), e);
			}
		}
		
		Session session  = HibernateManager.getSession();
		Query query = session.createQuery("select count(*) from "+className+" Where halltype=:TYPE");
		query.setString("TYPE", halltype);
		long count  = (long) query.uniqueResult();
		HibernateManager.endSession();
		return Integer.valueOf(String.valueOf(count));
	}
	
	/**
	 * [按照順序]讀取該比值所有機台
	 */
	public Object getMachineData(String modelName, String hallType, BigDecimal gainRate) {
		Session session = HibernateManager.getSession();
		Query query = session.createQuery("from " + modelName + " Where halltype=:TYPE and gainRate=:GAIN order by machineid");
		query.setFirstResult(0);
		query.setString("TYPE", hallType);
		query.setBigDecimal("GAIN", gainRate);
		Object result = (Object)query.list();
		HibernateManager.endSession();
		return result;
	}
	
	/**
	 * 讀取機台資料
	 * @param modelName
	 * @param halltype
	 * @param size
	 * @return
	 */
	public Object getMachineData(String modelName , String halltype , int size)
	{
		Session session  = HibernateManager.getSession();
		Query query = session.createQuery("from "+modelName+" Where halltype=:TYPE order by machineid");
		query.setFirstResult(0);
		query.setMaxResults(size);
		query.setString("TYPE", halltype);
		Object result = (Object)query.list();
		HibernateManager.endSession();
		return result;
	}
	
	/**
	 * 創建機台資訊(saveOrUpdate)
	 * @return
	 */
	public boolean createGameMachine(Object model)
	{
		Session session = HibernateManager.txBegin();
		session.saveOrUpdate(model);
		return HibernateManager.txCommitFailRollbackClearSession();
	}
	
	@SuppressWarnings("unchecked")
	public static <T extends List<?>> T castObjToList(Object obj) {
	    return (T) obj;
	}
	
	/**
	 * 隨機盤面讀取
	 * @param type 
	 * @param wheelCount
	 * @param col (欄) 
	 * @param row(列)
	 * @param symbol => TYPE_ARRANGE = 帶入所有wheel 排列帶組合  , TYPE_NO_ARRANGE =帶一組symbol 組合
	 * symbol 位置排列方式
	 *  1  , 2  ,  3  ,  4 , 5
	 *  6  , 7  ,  8  ,  9 ,10
	 *  11, 12, 13, 14,15
	 * @return
	 */
	public String randScreenSymbol(int type , int wheelCount , int col , int row ,ArrayList<ArrayList<Integer>> symbol)
	{
		ArrayList<Integer> screen = new ArrayList<Integer>(wheelCount);
		for(int v=0;v<wheelCount;v++)
		{
			screen.add(0);
		}
		
		
		
		int max_size = (type==TYPE_NO_ARRANGE)? wheelCount:col;
		for(int i=0;i<max_size;i++)
		{
			ArrayList<Integer> ss = (type==TYPE_NO_ARRANGE)? symbol.get(0):symbol.get(i);
			if(type==TYPE_NO_ARRANGE)
			{
				int idx = GameUtility.randomInt(0,ss.size()-1);
				screen.add(ss.get(idx));				
			}
			else if(type==TYPE_ARRANGE)
			{
				int idx = GameUtility.randomInt(0,ss.size()-1);
				
				int tmp_row = 0;
				do
				{
					screen.set(i + (tmp_row * col), ss.get(idx));	
					tmp_row++;
					idx++;
					if(idx == ss.size())
					{
						idx=0;
					}
				}
				while(tmp_row < row);
			}
		}
		
		return Arrays.toString(screen.toArray());
	}
	
	/**
	 * 隨機盤面讀取
	 * @param type 
	 * @param wheelCount
	 * @param col (欄) 
	 * @param row(列)
	 * @param symbol => TYPE_ARRANGE = 帶入所有wheel 排列帶組合  , TYPE_NO_ARRANGE =帶一組symbol 組合
	 * symbol 位置排列方式
	 *  1  , 2  ,  3  ,  4 , 5
	 *  6  , 7  ,  8  ,  9 ,10
	 *  11, 12, 13, 14,15
	 * @return
	 */
	public ArrayList<Integer> randScreenSymbolByArray(int type , int wheelCount , int col , int row ,ArrayList<ArrayList<Integer>> symbol)
	{
		ArrayList<Integer> screen = new ArrayList<Integer>(wheelCount);
		for(int v=0;v<wheelCount;v++)
		{
			screen.add(0);
		}
		
		
		
		int max_size = (type==TYPE_NO_ARRANGE)? wheelCount:col;
		for(int i=0;i<max_size;i++)
		{
			ArrayList<Integer> ss = (type==TYPE_NO_ARRANGE)? symbol.get(0):symbol.get(i);
			if(type==TYPE_NO_ARRANGE)
			{
				int idx = GameUtility.randomInt(0,ss.size()-1);
				screen.add(ss.get(idx));				
			}
			else if(type==TYPE_ARRANGE)
			{
				int idx = GameUtility.randomInt(0,ss.size()-1);
				
				int tmp_row = 0;
				do
				{
					screen.set(i + (tmp_row * col), ss.get(idx));	
					tmp_row++;
					idx++;
					if(idx == ss.size())
					{
						idx=0;
					}
				}
				while(tmp_row < row);
			}
		}
		
		return screen;
	}
	
}
